﻿using System.Collections.Generic;
using Metro.Kashikoi.Service.Common.Entity;
using Metro.Kashikoi.Service.Item.Business;
using Metro.Kashikoi.Service.Item.Entity;
using Metro.Kashikoi.ServiceContract;
using Metro.Kashikoi.ServiceContract.Item;
using Metro.Kashikoi.ServiceContract.Storage;

namespace Metro.Kashikoi.Service.Item.Service
{
    /// <summary>
    /// This class implements the interface <c>IItemService</c>, <c>ICategoryService</c> and <c>IVendorService</c>.
    /// </summary>
    class ItemService : IItemService, ICategoryService, IVendorService
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ItemService"/> class.
        /// </summary>
        public ItemService()
        {
            this.VendorFacade = new VendorFacade();
            this.CategoryFacade = new CategoryFacade();
            this.ItemFacade = new ItemFacade();
            this.Factory = new UnitOfWorkFactory();
        }

        private IStorageService StorageService { get { return ServiceBus.GetService<IStorageService>(); } }

        private IVendorFacade VendorFacade { get; set; }
        private IItemFacade ItemFacade { get; set; }
        private ICategoryFacade CategoryFacade { get; set; }
        private IUnitOfWorkFactory Factory { get; set; }

        #region IItemService Members

        /// <summary>
        /// Creates a new item.
        /// </summary>
        /// <param name="item">The item to be created.</param>
        /// <returns>
        /// The newly created item.
        /// </returns>
        public StockItem CreateItem(StockItem item)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                // Replace the object with the entity object.
                var category = CategoryFacade.GetCategory(ctx, item.Category.Id);
                var vendor = VendorFacade.GetVendor(ctx, item.Vendor.Id);

                ItemFacade.CreateItem(ctx, item, category, vendor);
                ctx.SaveChanges();
            }
            return item;
        }

        /// <summary>
        /// Updates the item.
        /// </summary>
        /// <param name="item">The item to be updated.</param>
        public void UpdateItem(StockItem item)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                // Get new category and vendor.
                var category = CategoryFacade.GetCategory(ctx, item.Category.Id);
                var vendor = VendorFacade.GetVendor(ctx, item.Vendor.Id);

                ItemFacade.UpdateItem(ctx, item, category, vendor);
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Deletes the item.
        /// </summary>
        /// <param name="itemId">The item id.</param>
        public void DeleteItem(int itemId)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                ItemFacade.DeleteItem(ctx, itemId);
                // Delete inventories of item.
                StorageService.DeleteInventoriesOfItems(new int[] { itemId });
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Gets all items.
        /// </summary>
        /// <returns>
        /// A list of item.
        /// </returns>
        public IList<StockItem> GetAllItems()
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                return ItemFacade.GetAllItems(ctx);
            }
        }

        /// <summary>
        /// Imports the items.
        /// </summary>
        /// <param name="path">The file path.</param>
        public void ImportItems(string path)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                ItemFacade.ImportItems(ctx, path);
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Creates the charge department.
        /// </summary>
        /// <param name="chargeDepartment">The charge department.</param>
        /// <returns>
        /// The newly created charge department.
        /// </returns>
        public ChargeDepartment CreateChargeDepartment(ChargeDepartment chargeDepartment)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                ItemFacade.CreateChargeDepartment(ctx, chargeDepartment);
                ctx.SaveChanges();
            }
            return chargeDepartment;
        }

        /// <summary>
        /// Updates the charge department.
        /// </summary>
        /// <param name="chargeDepartment">The charge department.</param>
        public void UpdateChargeDepartment(ChargeDepartment chargeDepartment)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                ItemFacade.UpdateChargeDepartment(ctx, chargeDepartment);
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Deletes the charge department.
        /// </summary>
        /// <param name="chargeDepartmentId">The charge department id.</param>
        public void DeleteChargeDepartment(int chargeDepartmentId)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                List<int> deletedItems = new List<int>();
                ItemFacade.DeleteChargeDepartment(ctx, chargeDepartmentId, deletedItems);
                // Delete inventories of the items of charge department.
                StorageService.DeleteInventoriesOfItems(deletedItems);
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Gets all charge departments.
        /// </summary>
        /// <returns>
        /// A list of charge department.
        /// </returns>
        public IList<ChargeDepartment> GetAllChargeDepartments()
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                return ItemFacade.GetAllChargeDepartments(ctx);
            }
        }

        /// <summary>
        /// Gets the item.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="includeCategory">if set to <c>true</c> 
        /// the category will be fetched.</param>
        /// <param name="includeVendor">if set to <c>true</c> 
        /// the vendor will be fetched.</param>
        /// <param name="includeChargeDepartment">if set to <c>true</c> 
        /// the charge department will be fetched..</param>
        /// <returns>
        /// The item.
        /// </returns>
        public StockItem GetItem(int id, bool includeCategory = true,
            bool includeVendor = true, bool includeChargeDepartment = true)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IItemService>())
            {
                return ItemFacade.GetItem(ctx, id, includeCategory, includeVendor,
                    includeChargeDepartment);
            }
        }

        #endregion

        #region ICategoryService Members

        /// <summary>
        /// Creates the category.
        /// </summary>
        /// <param name="category">The category to be created.</param>
        /// <returns>
        /// The newly created category.
        /// </returns>
        public ColorCategory CreateCategory(ColorCategory category)
        {
            using (IUnitOfWork ctx = Factory.GetContext<ICategoryService>())
            {
                CategoryFacade.CreateCategory(ctx, category);
                ctx.SaveChanges();
            }
            return category;
        }

        /// <summary>
        /// Updates the category.
        /// </summary>
        /// <param name="category">The category to be updated.</param>
        public void UpdateCategory(ColorCategory category)
        {
            using (IUnitOfWork ctx = Factory.GetContext<ICategoryService>())
            {
                CategoryFacade.UpdateCategory(ctx, category);
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Deletes the category.
        /// </summary>
        /// <param name="categoryId">The category id.</param>
        public void DeleteCategory(int categoryId)
        {
            using (IUnitOfWork ctx = Factory.GetContext<ICategoryService>())
            {
                CategoryFacade.DeleteCategory(ctx, categoryId);
                IList<int> deletedItems = new List<int>();
                ItemFacade.DeleteItemsOfCategory(ctx, categoryId, deletedItems);
                // TODO Delete the inventories of items.
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Gets the category by id.
        /// </summary>
        /// <param name="id">The category id.</param>
        /// <returns>
        /// The category with specific id.
        /// </returns>
        public ColorCategory GetCategory(int id)
        {
            using (IUnitOfWork ctx = Factory.GetContext<ICategoryService>())
            {
                return CategoryFacade.GetCategory(ctx, id);
            }
        }

        /// <summary>
        /// Gets all the categories.
        /// </summary>
        /// <returns>
        /// A list of the category.
        /// </returns>
        public IList<ColorCategory> GetAllCategories()
        {
            using (IUnitOfWork ctx = Factory.GetContext<ICategoryService>())
            {
                return CategoryFacade.GetAllCategories(ctx);
            }
        }

        #endregion

        #region IVendorService Members

        /// <summary>
        /// Creates the vendor.
        /// </summary>
        /// <param name="vendor">The vendor.</param>
        /// <returns>
        /// The newly created vendor.
        /// </returns>
        public Vendor CreateVendor(Vendor vendor)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IVendorService>())
            {
                VendorFacade.CreateVendor(ctx, vendor);
                ctx.SaveChanges();
            }
            return vendor;
        }

        /// <summary>
        /// Updates the vendor.
        /// </summary>
        /// <param name="vendor">The vendor.</param>
        public void UpdateVendor(Vendor vendor)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IVendorService>())
            {
                VendorFacade.UpdateVendor(ctx, vendor);
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Deletes the vendor.
        /// </summary>
        /// <param name="vendorId">The vendor id.</param>
        public void DeleteVendor(int vendorId)
        {
            using (IUnitOfWork ctx = Factory.GetContext<IVendorService>())
            {
                VendorFacade.DeleteVendor(ctx, vendorId);
                IList<int> deletedItems = new List<int>();
                ItemFacade.DeleteItemsOfVendor(ctx, vendorId, deletedItems);
                // TODO Delete inventories of items.
                ctx.SaveChanges();
            }
        }

        /// <summary>
        /// Gets all vendors.
        /// </summary>
        /// <returns>
        /// A list of vendor.
        /// </returns>
        public IList<Vendor> GetAllVendors()
        {
            using (IUnitOfWork ctx = Factory.GetContext<IVendorService>())
            {
                return VendorFacade.GetAllVendors(ctx);
            }
        }

        #endregion
    }
}
